import { defineVirtualModule, generageImports } from './_utils'
import utilsModule from './utils'

export default defineVirtualModule(
  'wasm-virutal:wasm-helper',
  `
  ${generageImports([utilsModule, ['readFile', 'readFileSync']])}

  if (typeof WebAssembly !== "object") {
    throw new Error("no native wasm support detected.");
  }

  const WebAssembly_instantiateBuffer = WebAssembly.instantiate;
  const WebAssembly_instantiateBufferSync = (buffer, importObject) => {
    const module = new WebAssembly.Module(buffer);
    const instance = new WebAssembly.Instance(module, importObject);
    return { instance };
  }

  const createInstantiateFromPath = (wasmPath, factory) => {
    let wasmSource, module;
    if (typeof factory !== "function") factory = (createInstance, importObject) => createInstance(importObject);
    const instantiate = async importObject => {
      let instance;
      if (!wasmSource) wasmSource = await readFile(wasmPath);
      const createInstance = async importObject => {
        let modSource;
        return (instance = module ? await WebAssembly.instantiate(module, importObject) : ((modSource = await WebAssembly.instantiate(wasmSource, importObject)), modSource.instance));
      };
      await factory(createInstance, importObject, true);
      return instance;
    };
  
    const instantiateSync = importObject => {
      let instance;
      if (!wasmSource) wasmSource = readFileSync(wasmPath);
      if (!module) module = new WebAssembly.Module(wasmSource);
      const createInstance = importObject => (instance = new WebAssembly.Instance(module, importObject));
      factory(createInstance, importObject, false);
      return instance;
    };
  
    return { instantiate, instantiateSync };
  };
  const createInstantiateFromBuffer = (wasmSource, factory) => {
    let module;
    if (typeof factory !== "function") factory = (createInstance, importObject) => createInstance(importObject);
    const instantiate = async importObject => {
      let instance;
      const createInstance = async importObject => {
        let modSource;
        return (instance = module ? await WebAssembly.instantiate(module, importObject) : ((modSource = await WebAssembly.instantiate(wasmSource, importObject)), modSource.instance));
      };
      await factory(createInstance, importObject, true);
      return instance;
    };
    const instantiateSync = importObject => {
      let instance;
      if (!module) module = new WebAssembly.Module(wasmSource);
      const createInstance = importObject => (instance = new WebAssembly.Instance(module, importObject));
      factory(createInstance, importObject, false);
      return instance;
    };
    return { instantiate, instantiateSync };
  };  
  `,
  [
    'createInstantiateFromPath',
    'createInstantiateFromBuffer',
    'WebAssembly_instantiateBuffer',
    'WebAssembly_instantiateBufferSync',
  ]
)
